package com.rainbow.idempotent.lock;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * 分布式锁顶级接口
 * 例如：
 * RETRY_TIMES=100，SLEEP_MILLIS=100
 * RETRY_TIMES * SLEEP_MILLIS = 10000 意味着如果一直获取不了锁，最长会等待10秒后抛超时异常
 *
 * @author gujiachun
 */
public interface DistributedLock {

    /**
     * 默认超时时间（即过期时间）（毫秒）
     */
    long TIMEOUT_MILLIS = 5000;

    /**
     * 等待的时间(毫秒)
     */
    long WAIT_MILLIS = 100;
    
    /**
     * 获取锁--阻塞中，一直等到拿到锁为止
     *
     * @param key key
     * @return 成功/失败
     */
    boolean lock(String key);
    
    /**
     * 加锁
     * @param key 锁Key
     * @param waitTime 尝试加锁，等待时间 (ms)
     * @param leaseTime 上锁后的失效时间 (ms)
     * @param success 锁成功执行的逻辑
     * @param fail 锁失败执行的逻辑
     * @return
     */
    <T> T lock(String key, long waitTime, long leaseTime, Supplier<T> success, Supplier<T> fail);

    /**
     * 加锁, 加锁失败立即返回
     * @param key 锁Key
     * @param leaseTime 上锁后的失效时间 (ms)
     * @param success 锁成功执行的逻辑
     * @param fail 锁失败执行的逻辑
     * @return
     */
    <T> T lock(String key, long leaseTime, Supplier<T> success, Supplier<T> fail);

    /**
     * 加锁, 加锁失败立即返回
     * @param key 锁Key
     * @param leaseTime 上锁后的失效时间
     * @param timeUnit 时间单位
     * @param success 锁成功执行的逻辑
     * @param fail 锁失败执行的逻辑
     * @return
     */
    <T> T lock(String key, long leaseTime, TimeUnit timeUnit, Supplier<T> success, Supplier<T> fail);

    /**
     * 加锁
     * @param key 锁Key
     * @param waitTime 尝试加锁，等待时间 (ms)
     * @param leaseTime 上锁后的失效时间 (ms)
     * @param success 锁成功执行的逻辑
     * @param fail 锁失败执行的逻辑
     * @return
     */
    void lock(String key, long waitTime, long leaseTime, Runnable success, Runnable fail);

    /**
     * 加锁, 加锁失败立即返回
     * @param key 锁Key
     * @param leaseTime 上锁后的失效时间 (ms)
     * @param success 锁成功执行的逻辑
     * @param fail 锁失败执行的逻辑
     * @return
     */
    void lock(String key, long leaseTime, Runnable success, Runnable fail);

    /**
     * 加锁, 加锁失败立即返回
     * @param key 锁Key
     * @param leaseTime 上锁后的失效时间
     * @param timeUnit 时间单位
     * @param success 锁成功执行的逻辑
     * @param fail 锁失败执行的逻辑
     * @return
     */
    void lock(String key, long leaseTime, TimeUnit timeUnit, Runnable success, Runnable fail);

    /**
     * 获取锁--立刻返回
     *
     * @param key key
     * @return 成功/失败
     */
    boolean tryLock(String key);

    /**
     * 获取锁--获取锁成功，并且设置锁的超时时间
     * 获取不到锁，立刻返回
     * 
     * @param key    key
     * @param expire 获取锁超时时间(毫秒为单位)
     * @return 成功/失败
     */
    boolean tryLock(String key, long expire);

    /**
     * 获取锁---不立刻返回，等待一段时间
     *
     * @param key        key
     * @param expire     获取锁超时时间 (毫秒为单位)
     * @param waitTimes  等待一段时间 (毫秒为单位)
     * @return 成功/失败
     */
    boolean tryLock(String key, long expire, long waitTimes);

    /**
     * 释放锁
     *
     * @param key key值
     * @return 释放结果
     */
    void releaseLock(String key);

}
